package com.canaan.common.encrypt;

import cn.hutool.core.util.StrUtil;
import org.apache.http.Header;
import org.apache.http.HttpStatus;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.ssl.TrustStrategy;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.SSLContext;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.List;

/**
 * @Description: 带连接池功能的Http工具类
 * @Author: du.tang
 * @Date: 2021/05/16
 */
public class HttpClientUtils {

    /**
     * user agent
     */
    private final static String UA = "RuiXing/99.81 Chrome/62.0.3202.94 Safari/537.36";
    /**
     * logger
     */
    private final static Logger logger = LoggerFactory.getLogger(HttpClientUtils.class);
    /**
     * 最大线程数
     */
    private static final int MAX_THREAD_NUM = 400;
    /**
     * 每个路由上最大连接数
     */
    private static final int DEFAULT_PER_ROUTE = 50;
    /**
     * 与服务端连接超时时间
     */
    private static final int CONNECT_TIMEOUT = 10000;
    /**
     * 从connect Manager获取Connection超时时间
     */
    private static final int CONNECTION_REQUEST_TIMEOUT = 10000;
    /**
     * SOCKET超时时间
     */
    private static final int SOCKET_TIMEOUT = 30000;
    /**
     * 连接池管理对象
     */
    private static PoolingHttpClientConnectionManager POOLINGHTTPCLIENTCONNECTIONMANAGER = null;

    static {
        POOLINGHTTPCLIENTCONNECTIONMANAGER = new PoolingHttpClientConnectionManager();
        POOLINGHTTPCLIENTCONNECTIONMANAGER.setMaxTotal(MAX_THREAD_NUM);
        POOLINGHTTPCLIENTCONNECTIONMANAGER.setDefaultMaxPerRoute(DEFAULT_PER_ROUTE);
        POOLINGHTTPCLIENTCONNECTIONMANAGER.setValidateAfterInactivity(50);
    }

    /**
     * 获取一个带连接池的client
     *
     * @return 带连接池的client
     * @throws Exception 创建异常
     */
    public static CloseableHttpClient httpClient() throws Exception {
        SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(null, new TrustStrategy() {
            @Override
            public boolean isTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
                return true;
            }
        }).build();
        //自定义重试策略,3次重试
        DefaultHttpRequestRetryHandler defaultHttpRequestRetryHandler = new DefaultHttpRequestRetryHandler(3, false);

        RequestConfig requestConfig = RequestConfig.custom()
                .setCookieSpec(CookieSpecs.IGNORE_COOKIES)
                .setConnectTimeout(CONNECT_TIMEOUT)
                .setConnectionRequestTimeout(CONNECTION_REQUEST_TIMEOUT)
                .setSocketTimeout(SOCKET_TIMEOUT).build();
        CloseableHttpClient httpClient = HttpClients.custom()
                //.setConnectionManager(POOLINGHTTPCLIENTCONNECTIONMANAGER)
                .setDefaultRequestConfig(requestConfig)
                .setRetryHandler(defaultHttpRequestRetryHandler)
                .setUserAgent(UA)
                .setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
                .setSSLContext(sslContext).build();
        return httpClient;
    }

    /**
     * http post 请求
     *
     * @param url        调用地址
     * @param paramsList 参数列表
     * @return 调用结果
     * @throws Exception 调用异常
     */
    public static String post(String url, List<BasicNameValuePair> paramsList) throws Exception {
        CloseableHttpClient httpClient = HttpClientUtils.httpClient();
        CloseableHttpResponse httpResponse = null;
        try {
            HttpPost httpPost = new HttpPost(url);
            UrlEncodedFormEntity urlEncodedFormEntity = new UrlEncodedFormEntity(paramsList, "UTF-8");
            httpPost.setEntity(urlEncodedFormEntity);
            // 设置中文
            httpPost.setHeaders(buildI18nHeader());
            httpResponse = httpClient.execute(httpPost);
            int stateCode = httpResponse.getStatusLine().getStatusCode();
            String content = "";
            if (stateCode == HttpStatus.SC_OK) {
                content = EntityUtils.toString(httpResponse.getEntity());
            } else {
                logger.error("Http调用异常，url:{},statusCode:{}", url, stateCode);
            }
            if (StrUtil.isBlank(content)) {
                throw new IllegalArgumentException("Http请求结果异常");
            }
            return content;
        } finally {
            if (httpResponse != null) {
                httpResponse.close();
            }
            if (httpClient != null) {
                httpClient.close();
            }
        }
    }

    private static Header[] buildI18nHeader() {
        Header country = new BasicHeader(I18NContextHolder.COUNTRY, "SG");
        Header language = new BasicHeader(I18NContextHolder.LANGUAGE, "zh");
        Header countryMdCode = new BasicHeader(I18NContextHolder.COUNTRY_MD_CODE, "SG");
        Header dataNodeCode = new BasicHeader(I18NContextHolder.DATA_NODE_CODE, "90");
        Header zoneId = new BasicHeader(I18NContextHolder.ZONE_ID, "Asia/Singapore");
        return new Header[]{country, language, countryMdCode, dataNodeCode, zoneId};
    }
}
